#ifndef AS3Model_h__
#define AS3Model_h__

#include "Opcode.h"
#include "ABCFile.h"
#include "swf/SWF.h"
#include "swf/SWFTypes.h"
#include "swf/SWFTagWrapper.h"
#include <QFileInfo>
#include <vector>
#include <string>

class TagDoABC;

class AS3ABCFile;
class AS3Cpool;
class AS3Class;
class AS3Interface;
class AS3Method;
class AS3MethodParam;
class AS3MethodBody;
class AS3Slot;
class AS3Type;

class AS3SWF
	: public SWFWrapper
{
private:
	SWF* _swf;
	bool _isAnalyze;
	std::vector<AS3ABCFile*> _abcVec;
	QFileInfo _swfFileInfo;
public:
	AS3SWF(SWF* swf, const QFileInfo& fileInfo);
	void getAllABCFiles(std::vector<AS3ABCFile*>& all);
	inline const QFileInfo& getFileInfo() const { return _swfFileInfo; }
	inline SWF* getRawSWF() const { return _swf; }
private:
	void analyze();
};

//////////////////////////////////////////////////////////////////////////
// AS3 base data
class AS3SWFObject
{
protected:
	AS3SWF* as3SWF;
public:
	AS3SWFObject();
	virtual void setSWF(AS3SWF* swf);
	inline AS3SWF* getSWF() const { return as3SWF; }
	virtual void analyze();
};

class AS3ABCFile
	: public AS3SWFObject
{
private:
	TagDoABC* _tag;
	ABCFile* _abcFile;
	AS3Cpool* _pool;
	std::vector<AS3Class*> _allClassesVec;
public:
	AS3ABCFile(TagDoABC* tagABC);
	~AS3ABCFile();
	AS3Cpool* getCpool() const;
	CpoolInfo* getRawCpool() const;
	ABCFile* getRawABCFile() const;
	size_t getClassCount() const;
	void getAllClasses(std::vector<AS3Class*>& all);
	std::string getName() const;
public:
	void analyze() override;
};

class AS3ABCFileObject
	: public AS3SWFObject
{
protected:
	AS3ABCFile* abcFile;
public:
	AS3ABCFileObject();
	virtual void setABCFile(AS3ABCFile* file);
	inline AS3ABCFile* getABCFile() const { return abcFile; }
};

class AS3Cpool
	: public AS3ABCFileObject
{
private:
	CpoolInfo* _poolInfo;
public:
	AS3Cpool(CpoolInfo* pool);
	~AS3Cpool();
};

class AS3Metadata
	: public AS3ABCFileObject
{
private:
	UI30 index;
public:
	AS3Metadata(UI30 idx) : index(idx) {};
	void analyze() override;
};

class AS3Type
	: public AS3ABCFileObject
{

};

class AS3Class
	: public AS3ABCFileObject
{
private:
	InstanceInfo* _instanceInfo;
	ClassInfo* _classInfo;
	std::string _name;
	std::string _package;
	std::vector<AS3Slot*> _slotsVec;
	std::vector<AS3Method*> _methodsVec;
	AS3Method* _cinitMethod;
	AS3Method* _iinitMethod;
public:
	AS3Class(ClassInfo* ci, InstanceInfo* ii);
	size_t getMethodsCount() const;
	void getAllMethods(std::vector<AS3Method*>& all);
	size_t getSlotsCount() const;
	void getAllSlots(std::vector<AS3Slot*>& all);
	AS3Method* getCinitMethod() const;
	AS3Method* getConstructor() const;
	bool isInterface() const;
	bool isFinal() const;
	size_t getInterfacesCount() const;
	void getAllInterfaces(std::vector<AS3Class*>& all);
	AS3Type* getSuperClass() const;
public:
	void analyze() override;
	std::string getShortName() const;
	std::string getPackageName() const;
};

class AS3ClassObject
	: public AS3ABCFileObject
{
protected:
	AS3Class* clazz;
public:
	AS3ClassObject();
	void setClass(AS3Class* clazz);
};

class AS3ClassMember
	: public AS3ClassObject
{
protected:
	TraitInfo* trait;
	QName* qName;
	NamespaceInfo* ns;
	std::vector<AS3Metadata*> metadatasVec;
public:
	AS3ClassMember(TraitInfo* ti);
	bool isPublic() const;
	bool isPrivate() const;
	bool isProtected() const;
	bool isStatic() const;
	bool hasMetadata() const;
	void getAllMetadata(std::vector<AS3Metadata*>& all);

	virtual std::string getShortName() const;
public:
	virtual void analyze() override;
};

class AS3Slot
	: public AS3ClassMember
{
private:
	TraitSlot* _traitSlot;
public:
	AS3Slot(TraitSlot* ti);
	bool isConst() const;
	void analyze() override;
};

//Method
//Getter
//Setter
class AS3Method
	: public AS3ClassMember
{
private:
	TraitMethod* _traitMethod;
	MethodInfo* _methodInfo;
	MethodBodyInfo* _methodBodyInfo;
	AS3MethodBody* _body;
public:
	AS3Method(TraitMethod* ti);
	AS3Method(MethodInfo* mi, MethodBodyInfo* bodyInfo);
	bool isConstruct() const;
	bool isGetter() const;
	bool isSetter() const;
	bool isOverride() const;
	bool isFinal() const;
	size_t getParamCount() const;
	AS3MethodParam* getParam(unsigned int index) const;
	void getAllParams(std::vector<AS3MethodParam*>& all) const;
	AS3Type* getReturnType() const;
	AS3MethodBody* getBody() const;
public:
	void analyze() override;
};

class AS3MethodParam
	: public AS3ClassObject
{
public:

};

class AS3MethodBody
	: public AS3ClassObject
{
public:
	size_t length;
	char* data;
private:
	MethodBodyInfo* _bodyInfo;
public:
	AS3MethodBody(MethodBodyInfo*);
	void analyze() override;
};

#endif // AS3Model_h__
